from time import sleep
import tkinter
from tkinter import ttk

from CustomClass import *


# //------------------------------------------最主要的功能函数--------------------------------------------------
def startWorking(open_time, closed_time):  # 运用变量模拟线程
    client_array_length = 1000  # 顾客数组最大长度
    window_length = 4  # 窗口数量
    client = list(Client() for i in range(client_array_length))  # 创建顾客链表
    # for i in range(len(client)):print(i,client[i].getClientArriveTime()) #测试快排
    low = 0;
    high = len(client) - 1
    quickSortClient(client, low, high)
    client_queue = LinkedQueue()
    client_queue.joinQueue(client, open_time, closed_time)
    lens = client_queue.getQueueLength()
    # for i in range(lens):print(client_queue.deleteQueue().getClientArriveTime()) #得到队元素
    # for i in range(len(client)):print(i,client[i].getClientArriveTime())#测试快排
    # 建立四个银行窗口
    windows = list(Bank(open_time, closed_time) for i in range(4))
    # print(windows[0])
    i = 0  # 用来控制遍历空窗口的循环
    j = 0  # 用来控制遍历业务办理时间最小窗口的循环
    count = 0  # 用来记录顾客所在窗口
    index_for_min = 0  # 记录结束时间最小的窗口下标
    bank_end_time = 0  # 记录银行结束营业时间
    now_temp_all_time_min = 0  # 记录当前办理时间最短的那个窗口的结束办理时间
    bank_end_time = windows[0].getBankClosedTime() * 60  # 将银行结束营业时间存储并转化为分钟表达。
    # -------------------------
    Bankdb = sqlite3.connect("Bankdb.db")  # 连接数据库
    cur = Bankdb.cursor()

    cur.execute("delete from custom")  # 删除用户数据的数据库

    # cur.execute("delete from windows") #删除窗口数据的数据库
    Bankdb.commit()

    Bankdb.close()
    # ------------------------------
    if client_queue.empty() == True:
        pass  # 如果等待队列一开始就为空的话那就退出
    else:
        while (
                client_queue.empty() != True and now_temp_all_time_min <= bank_end_time):  # 只要队列还有元素或者此时办理时间最小的窗口的总时间没超银行营业结束时间
            # 如果窗口都不为空
            if not windows[0].getWindowsEmpty() and not windows[1].getWindowsEmpty() \
                    and not windows[2].getWindowsEmpty() and not windows[3].getWindowsEmpty():
                index_for_min = getMinTimeByWindow(windows, window_length)  # 调用找最小下标的找到业务办理结束时间最小的窗口
                windows[index_for_min].setWindowsEmpty(True)  # 时间最小的窗口设置为没人状态
                windows[index_for_min].setBusinessStartTime(
                    windows[index_for_min].getbusinessEndTime())  # 将最快办理完毕的窗口的下一个业务开始办理时间设置为它上一个业务办理的结束时间
                now_temp_all_time_min = windows[index_for_min].getbusinessEndTime()  # 将此时办理时间最短的窗口的时间设置为总时间
                setWindowStatusByBankEndTime(windows, window_length,
                                             bank_end_time)  # 找到此时服务时间超过了银行营业时间的窗口，并将它关闭，意味着它不再接受客人
                # print("程序运行中")

            else:  # 否则执行业务办理
                # 执行出队操作
                # print("程序运行中")
                client = client_queue.deleteQueue()  # 用一个临时对象来存储当前出队对象

                for i in range(window_length):
                    count = i
                    if windows[i].getWindowsEmpty() == True:  # 找到当前空的窗口并输出打印
                        print("当前到来顾客在第", i + 1, "号窗口办理业务")
                        client.showClientInfor()  # 打印当前办理业务的客户的票的信息
                        print()
                        print()
                        # 如果此时到达该窗口的用户的时间远大于窗口上一个业务办理完毕的时间（也就是该窗口业务下一个业务开始时间）
                        # 那么就将该业务下一个业务开始时间 = 下一个顾客到来的时间
                        if client.getClientArriveTime() > windows[i].getBusinessStartTime():
                            windows[i].setBusinessStartTime(client.getClientArriveTime())
                        windows[i].setWindowsEmpty(False)  # 将该窗口设置为有人状态
                        case = client.getClientBusinessName()
                        if case == 0:
                            # 设置当前窗口办理结束时间为，窗口上一个人办理完毕的时间 + 当前到来顾客需要办理的时间
                            windows[i].setbusinessEndTime(
                                windows[i].getBusinessStartTime() + client.getClientBusinessNameTime())
                            # 户逗留时间 = 用户离开的时间（窗口服务当前客户结束时间）- 用户到达的时间
                            windows[i].setClientStayBankTime(
                                (windows[i].getbusinessEndTime() - client.getClientArriveTime()))
                            windows[i].setSaveMoneyNum()  # 当前窗口的存款办理次数+1
                        elif case == 1:
                            # 设置当前窗口办理结束时间为，窗口上一个人办理完毕的时间 + 当前到来顾客需要办理的时间
                            windows[i].setbusinessEndTime(
                                windows[i].getBusinessStartTime() + client.getClientBusinessNameTime())
                            # 户逗留时间 = 用户离开的时间（窗口服务当前客户结束时间）- 用户到达的时间
                            windows[i].setClientStayBankTime(
                                (windows[i].getbusinessEndTime() - client.getClientArriveTime()))
                            windows[i].setGetMoneyNum()  # 当前窗口的取款办理次数+1
                        elif case == 2:
                            # 设置当前窗口办理结束时间为，窗口上一个人办理完毕的时间 + 当前到来顾客需要办理的时间
                            windows[i].setbusinessEndTime(
                                windows[i].getBusinessStartTime() + client.getClientBusinessNameTime())
                            # 户逗留时间 = 用户离开的时间（窗口服务当前客户结束时间）- 用户到达的时间
                            windows[i].setClientStayBankTime(
                                (windows[i].getbusinessEndTime() - client.getClientArriveTime()))
                            windows[i].setReportLossOfNum()  # 当前窗口的挂失办理次数+1
                        elif case == 3:
                            # 设置当前窗口办理结束时间为，窗口上一个人办理完毕的时间 + 当前到来顾客需要办理的时间
                            windows[i].setbusinessEndTime(
                                windows[i].getBusinessStartTime() + client.getClientBusinessNameTime())
                            # 户逗留时间 = 用户离开的时间（窗口服务当前客户结束时间）- 用户到达的时间
                            windows[i].setClientStayBankTime(
                                (windows[i].getbusinessEndTime() - client.getClientArriveTime()))
                            windows[i].setRefundNum()  # 当前窗口的贷款办理次数+1
                        else:
                            print("error")

            sleep(0.1)  # 每执行一次循环就睡眠0.5秒模拟顾客缓缓到来
        print("程序运行结束")
        # -----------------------------用户数据窗口弹出------------------------------------
        Bankdb = sqlite3.connect("Bankdb.db")  # 连接数据库
        cur = Bankdb.cursor()
        cur.execute("select * from custom ")
        data1 = cur.fetchall()  # 用户数据
        row1 = len(data1)

        win = tkinter.Tk()
        win.title("用户数据")
        win.geometry("600x600+200+200")
        tree = ttk.Treeview(win)
        tree.pack()
        tree["columns"] = ('id', '办理总时间', '业务种类')
        tree.column('id', width=120)
        tree.column('办理总时间', width=200)
        tree.column('业务种类', width=200)

        tree.heading('id', text='id')
        tree.heading('办理总时间', text='办理总时间(分钟)')
        tree.heading('业务种类', text='业务种类')
        for i in range(row1):
            tree.insert("", 0, text=row1 - i, value=data1[i])
        win.mainloop()
        Bankdb.commit()
        Bankdb.close()

        # --------------------------------------------------------窗口数据窗口弹出--------------------------------
        Bankdb = sqlite3.connect("Bankdb.db")  # 连接数据库
        cur = Bankdb.cursor()
        cur.execute("select * from windows")
        data2 = cur.fetchall()  # 窗口数据
        print(data2)
        row2 = len(data2)
        win = tkinter.Tk()
        win.title("窗口数据")
        win.geometry("1200x1200+200+200")
        tree = ttk.Treeview(win)
        tree.pack()
        tree["columns"] = ('窗口', '存款办理次数', '取款办理次数', '挂失办理次数', '贷款办理次数', '窗口总计接纳人数')
        tree.column('窗口', width=120)
        tree.column('存款办理次数', width=200)
        tree.column('取款办理次数', width=200)
        tree.column('挂失办理次数', width=200)
        tree.column('贷款办理次数', width=200)
        tree.column('窗口总计接纳人数', width=200)

        tree.heading('窗口', text='窗口')
        tree.heading('存款办理次数', text='存款办理次数')
        tree.heading('取款办理次数', text='取款办理次数')
        tree.heading('挂失办理次数', text='挂失办理次数')
        tree.heading('贷款办理次数', text='贷款办理次数')
        tree.heading('窗口总计接纳人数', text='窗口总计接纳人数')
        for i in range(row2):
            tree.insert("", 0, text=row2 - i, value=data2[i])

        win.mainloop()
        Bankdb.commit()

        Bankdb.close()

        statisticData(windows, window_length)  # 输出客户平均逗留时间
        # startAnotherSimulate()


def startAnotherSimulate():
    select = 0
    print("Ready to leave and get another data？If you ready to leave please inputed the “1 ”：")
    while (select != 1):
        select = int(input(":"))
        if select != 1:
            print("input error,please input again（you need to inputed the  “1 ”！！！）")


def statisticData(window, window_length):
    i = 0  # 用来控制循环
    client_all_stay_time = 0  # 客户总的逗留时间
    all_client_num = 0  # 今日总到客量
    client_average_time = 0.0  # 客户今日平均逗留时间
    for i in range(window_length):
        # 顾客逗留总时间为：所有窗口的客户逗留时间累加
        client_all_stay_time += window[i].getClientStayBankTime()
        # 今日总到客量为：所有窗口的所有业务办理量的累加
        all_client_num += (
                    window[i].getGetMoneyNum() + window[i].getSaveMoneyNum() + window[i].getReportLossOfNum() + window[
                i].getRefundNum())
    # 输出窗口的信息:
    showAllWindow(window, window_length)
    client_average_time = client_all_stay_time / all_client_num  # 客户一天平均逗留时间 = 客户今日总逗留时间 / 今日到客总量
    print("今日客户平均逗留时间", round(client_average_time, 2), "分")  # 输出时间并保留两位小数


def showAllWindow(window, window_length):
    i = 0
    count = 0
    for i in range(window_length):
        print("窗口", i + 1, "的存款办理次数：", window[i].getSaveMoneyNum(), "取款办理次数：", window[i].getGetMoneyNum()
              , "挂失办理次数：", window[i].getReportLossOfNum(), "贷款办理次数：", window[i].getRefundNum())
        print("该窗口总计接纳人数：", (
                    window[i].getSaveMoneyNum() + window[i].getGetMoneyNum() + window[i].getReportLossOfNum() + window[
                i].getRefundNum()))
        print()
        count += 1
        # -----------------------------------业务统计窗口数据导入---------------------------
        Bankdb = sqlite3.connect("Bankdb.db")
        cur = Bankdb.cursor()
        # cur.execute("create table windows(window_num integer(4),SaveMoneyNum integer(4),GetMoneyNum integer(4),ReportLossOfNum integer(4),RefundNum integer(4),totalNums integer(4))")
        cur.execute("insert into windows values(?,?,?,?,?,?)", (
        i + 1, window[i].getSaveMoneyNum(), window[i].getGetMoneyNum(), window[i].getReportLossOfNum(),
        window[i].getRefundNum(), window[i].getTotalNums()))
        Bankdb.commit()
        Bankdb.close()


# -------------------------------------------------------------------------------------------------

'''
快速排序，用来对客户数组按升序排序
	参数一：Client类的对象数组
	参数二：对象数组的长度 
'''


def quickSortClient(client, low, high):
    if low < high:
        pi = partition(client, low, high)
        quickSortClient(client, low, pi - 1)
        quickSortClient(client, pi + 1, high)


'''统计一天客户在银行的平均逗留时间
	参数一：Bank类的对象数组
	参数二：对象数组的长度 
'''


def partition(client, low, high):
    i = (low - 1)  # 最小元素索引
    pivot = client[high].getClientArriveTime()

    for j in range(low, high):
        # 当前元素小于或等于 pivot
        if client[j].getClientArriveTime() <= pivot:
            i = i + 1
            client[i], client[j] = client[j], client[i]

    client[i + 1], client[high] = client[high], client[i + 1]
    return (i + 1)


# ----------------------------------------下列方法是辅助startWorking方法的子方法
'''找到此时服务时间超过了银行营业时间的窗口，并将它关闭 
	参数一：Bank类的名为window的对象数组
	参数二：对象数组的长度
	参数三：银行关门时间'''


def setWindowStatusByBankEndTime(window, window_length, bank_end_time):
    i = 0
    for i in range(window_length):
        if window[i].getBusinessStartTime() >= bank_end_time:
            window[i].setWindowsEmpty(False)


'''找到业务办理结束时间最小的窗口 
	参数一：Bank类的名为window的对象数组
	参数二：对象数组的长度'''


def getMinTimeByWindow(window, window_length):
    i = 0
    index = 0
    min = window[0].getbusinessEndTime()
    for i in range(window_length):
        if (min >= window[i].getbusinessEndTime()):
            min = window[i].getbusinessEndTime()
            index = i  # 记录结束时间最小的窗口下标
    return index  # 放回窗口数组中办理时间最短的那个窗口的下标
